package com.fubowen.lepton.conf

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.cachedIn
import androidx.paging.flatMap
import com.fubowen.lepton.extension.toTarget
import com.fubowen.lepton.helper.DBHelper
import com.fubowen.lepton.ui.reader.book.TextPaging
import com.fubowen.lepton.ui.reader.recycler.BookChapter
import com.fubowen.lepton.ui.reader.recycler.BookChapterPagingSource
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch

const val NAMESPACE = "READER_"
const val NAMESPACE_CONTENT = NAMESPACE + "CONTENT_"
const val TEXT_SIZE = NAMESPACE_CONTENT + "TEXT_SIZE"
const val LINE_SPACING_MULTIPLIER = NAMESPACE_CONTENT + "LINE_SPACING_MULTIPLIER"
const val LINE_SPACING_EXTRA = NAMESPACE_CONTENT + "LINE_SPACING_EXTRA"
const val HEIGHT = NAMESPACE_CONTENT + "HEIGHT"
const val WIDTH = NAMESPACE_CONTENT + "WIDTH"

const val NAMESPACE_HEADER = NAMESPACE + "HEADER_"
const val HEADER_TEXT_SIZE = NAMESPACE_HEADER + "TEXT_SIZE"
const val HEADER_LINE_SPACING_MULTIPLIER = NAMESPACE_HEADER + "LINE_SPACING_MULTIPLIER"
const val HEADER_LINE_SPACING_EXTRA = NAMESPACE_HEADER + "LINE_SPACING_EXTRA"
const val HEADER_HEIGHT = NAMESPACE_HEADER + "HEIGHT"
const val HEADER_WIDTH = NAMESPACE_HEADER + "WIDTH"


open class ReaderViewModel : ViewModel() {

    private val mChapterContent = TextPaging(0f, 0f, 60f)
    private val mChapterHeader = TextPaging(0f, 0f, 60f)
    private var mIsInitBookSetting = false

    //region 阅读器设置
    fun setHeight(height: Float) {
        mChapterContent.setHeight(height)
        mChapterHeader.setHeight(height)
    }

    fun setBackgroundColor(bgColor: Int) {
        mChapterContent.setBackgroundColor(bgColor)
        mChapterHeader.setBackgroundColor(bgColor)
    }

    fun setColor(color: Int) {
        mChapterContent.setTextColor(color)
        mChapterHeader.setTextColor(color)
    }

    fun setTheme(height: Float) {
        mChapterContent.setHeight(height)
        mChapterHeader.setHeight(height)
    }

    fun setWidth(width: Float) {
        mChapterContent.setWidth(width)
        mChapterHeader.setWidth(width)
    }

    fun setTextSize(value: Float?, isSave: Boolean = false) {
        if (value != null) {
            mChapterContent.textSize = value
            if (isSave) {
                saveSetting(TEXT_SIZE, value)
            }
        }
    }

    fun addTextSize(value: Float?, isSave: Boolean = false) {
        if (value != null) {
            val newValue = mChapterContent.textSize + value
            setTextSize(newValue, isSave)
        }
    }

    fun subTextSize(value: Float?, isSave: Boolean = false) {
        if (value != null) {
            val newValue = mChapterContent.textSize - value
            setTextSize(newValue, isSave)
        }
    }

    fun setLineSpacingMultiplier(value: Float?, isSave: Boolean = false) {
        if (value != null) {
            mChapterContent.lineSpacingMultiplier = value
            if (isSave) {
                saveSetting(LINE_SPACING_MULTIPLIER, value)
            }
        }
    }

    fun setLineSpacingExtra(value: Float?, isSave: Boolean = false) {
        if (value != null) {
            mChapterContent.lineSpacingExtra = value
            if (isSave) {
                saveSetting(LINE_SPACING_EXTRA, value)
            }
        }

    }

    fun setHeaderTextSize(value: Float?, isSave: Boolean = false) {
        if (value != null) {
            mChapterContent.textSize = value
            if (isSave) {
                saveSetting(HEADER_TEXT_SIZE, value)
            }
        }
    }

    fun setHeaderLineSpacingMultiplier(value: Float?, isSave: Boolean = false) {
        if (value != null) {
            mChapterContent.lineSpacingMultiplier = value
            if (isSave) {
                saveSetting(HEADER_LINE_SPACING_MULTIPLIER, value)
            }
        }
    }

    fun setHeaderLineSpacingExtra(value: Float?, isSave: Boolean = false) {
        if (value != null) {
            mChapterContent.lineSpacingExtra = value
            if (isSave) {
                saveSetting(HEADER_LINE_SPACING_EXTRA, value)
            }
        }

    }
    //endregion

    //region 保存阅读进度
    private var mUpdateJob: Job? = null
    private var mLastUpdateProgress = Triple(-1, 0, 0)
    private fun saveReadingProgress(progress: Triple<Int, Int, Int>) =
        viewModelScope.launch {
            val (bookId, id, charIndex) = progress
            DBHelper.db.bookDao().changeReadingChapter(bookId, id, charIndex)
        }

    fun sendReadingProgress(progress: Triple<Int, Int, Int>) {
        val (oldBookId, oldChapterId, _) = mLastUpdateProgress
        val (newBookId, newChapterId, _) = progress
        if (oldBookId == -1) {
            saveReadingProgress(progress)
        } else {
            if (oldBookId != newBookId) {
                saveReadingProgress(mLastUpdateProgress)
                saveReadingProgress(progress)
            } else if (oldChapterId != newChapterId) {
                saveReadingProgress(mLastUpdateProgress)
                saveReadingProgress(progress)
            } else {
                mUpdateJob?.cancel()
                mUpdateJob = viewModelScope.launch {
                    delay(300)
                    if (isActive) {
                        saveReadingProgress(progress)
                    }
                }
            }
        }
        mLastUpdateProgress = progress
    }
    //endregion

    //region 书籍章节

    private fun initReaderSetting() {
        if (!mIsInitBookSetting) {
            val map = DBHelper.db.settingDao().map()
            setHeaderTextSize(map[HEADER_TEXT_SIZE].toTarget<Float>())
            setHeaderLineSpacingMultiplier(map[HEADER_LINE_SPACING_MULTIPLIER].toTarget<Float>())
            setHeaderLineSpacingExtra(map[HEADER_LINE_SPACING_EXTRA].toTarget<Float>())

            setTextSize(map[TEXT_SIZE].toTarget<Float>())
            setLineSpacingMultiplier(map[LINE_SPACING_MULTIPLIER].toTarget<Float>())
            setLineSpacingExtra(map[LINE_SPACING_EXTRA].toTarget<Float>())
            mIsInitBookSetting = true
        }
    }

    fun bookChapterFlow(bookId: Int): Flow<PagingData<BookChapter>> {
        val pageSize = 1
        val pageConfig = PagingConfig(
            pageSize = pageSize,
            initialLoadSize = pageSize
        )
        initReaderSetting()
        return Pager(pageConfig) { BookChapterPagingSource(bookId) }
            .flow
            .map {
                it.flatMap { chapter ->
                    chapter.textSize = mChapterContent.textSize
                    chapter.lineSpacingMultiplier = mChapterContent.lineSpacingMultiplier
                    chapter.lineSpacingExtra = mChapterContent.lineSpacingExtra
                    chapter.backgroundColor = mChapterContent.bgColor
                    chapter.textColor = mChapterContent.color

                    chapter.headerTextSize = mChapterHeader.textSize
                    chapter.headerLineSpacingMultiplier = mChapterHeader.lineSpacingMultiplier
                    chapter.headerLineSpacingExtra = mChapterHeader.lineSpacingExtra
                    val height = mChapterHeader.getTextHeight(chapter.name)
                    mChapterContent.toPaging(
                        chapter.content,
                        Triple(1, TextPaging.Space.HEIGHT_USED_SPACE, height)
                    ) { page, index ->
                        val item = chapter.copy()
                        item.content = page.joinToString("")
                        item.isPageStart = index == 0
                        item
                    }
                }
            }
            .cachedIn(viewModelScope)
    }
    //endregion

    private fun saveSetting(key: String, value: Any?) {
        viewModelScope.launch {
            DBHelper.db.settingDao().set(key, value?.toString())
        }
    }

}